
package iks.render.anim 
{
	import flash.display.*;
	import flash.geom.*;
	import iks.event.*;
	import iks.iface.*;
	import iks.utils.*;
	
	/**
	 * 实现纹理的动画, 使用位图序列实现动画效果, 基于Flash的 ENTER_FRAME 事件计时, 
	 * 使用计时器更新帧, 动画帧率更新不会快过舞台场景帧率, 帧计数从 0 开始.
	 * 新生成的 KBitmapAnimator 对象是没有显示对象的, 即: 其 bitmapData 属性是 null. 必须调用 play, stop, gotoAndPlay, gotoAndStop, nextFrame, prevFrame 函数才会给其 bitmapData 对象赋予动画帧.
	 * @author StefanieKaka
	 */
	public final class KBitmapAnimator extends Bitmap implements IKDispose, IKClonable
	{
		/**
		 * 构造函数
		 * @param	animatorInfo 动画数据信息
		 * @param	frameDuration 每一帧的间隔时间, 以毫秒为单位
		 */
		public function KBitmapAnimator(animatorInfo : KBitmapAnimatorInfo, frameDuration : Number) 
		{
			m_animatorInfo = animatorInfo;
			m_totalFrame = animatorInfo.getTotalFrame();
			
			m_timer = new AnimatorTimer(frameDuration);
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 公共域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * 继续播放动画, 从当前帧开始继续播放, 当动画播放结束的时候, pause 函数将没有作用.
		 */
		public function resume() : void
		{
			if (!m_isFinished)
				m_isPlaying = true;
		}
		
		/**
		 * 暂停播放, 停止在当前帧, 当动画播放结束的时候, resume 函数将没有作用.
		 */
		public function pause() : void
		{
			if (!m_isFinished)
				m_isPlaying = false;
		}
		
		/**
		 * 停止播放, 回到起始帧
		 */
		public function stop() : void
		{
			if (!m_isPlayback)
				m_currentFrame = 0;
			else
				m_currentFrame = m_totalFrame - 1;
				
			gotoAndStop(m_currentFrame);
		}
		
		/**
		 * 从起始帧开始播放
		 * @param	repeatCount 播放次数, -1表示循环播放, 0表示播放一次, 1两次, 以此类推...
		 * @param	isPlayback 是否倒序播放, 默认顺序播放
		 */
		public function play(repeatCount : int = -1, isPlayback : Boolean = false) : void
		{
			if (isPlayback)
				m_currentFrame = m_totalFrame - 1;
			else
				m_currentFrame = 0;
			
			gotoAndPlay(m_currentFrame, repeatCount, isPlayback);
		}
		
		/**
		 * 跳到下一帧
		 */
		public function nextFrame() : void
		{
			if (!m_isPlayback)
			{
				if (m_currentFrame == m_totalFrame - 1)
					m_currentFrame = 0;
				else
					++m_currentFrame;
			}
			else
			{
				if (m_currentFrame == 0)
					m_currentFrame = m_totalFrame - 1;
				else
					--m_currentFrame;
			}
			
			createNewFrame(m_currentFrame);
			
			// 下一帧会重新开始计时
			m_timer.reset();
		}
		
		/**
		 * 跳回上一帧
		 */
		public function prevFrame() : void
		{
			if (!m_isPlayback)
			{
				if (m_currentFrame == 0)
					m_currentFrame = m_totalFrame - 1;
				else
					--m_currentFrame;
			}
			else
			{
				if (m_currentFrame == m_totalFrame - 1)
					m_currentFrame = 0;
				else
					++m_currentFrame;
			}
			
			createNewFrame(m_currentFrame);
			
			// 下一帧会重新开始计时
			m_timer.reset();
		}
		
		/**
		 * 跳到指定帧并且播放
		 * @param	frame 跳到的指定帧, 帧计数从 0 开始
		 * @param	repeatCount 播放次数, -1表示循环播放, 0表示播放一次, 1两次, 以此类推...
		 * @param	isPlayback 播放方式
		 */
		public function gotoAndPlay(frame : int, repeatCount : int = -1, isPlayback : Boolean = false) : void
		{
			m_isPlaying = true;
			m_isFinished = false;
			m_isPlayback = isPlayback;
			m_repeatCount = repeatCount;
			m_currentFrame = frame;
			createNewFrame(m_currentFrame);
			
			// 下一帧会重新开始计时
			m_timer.reset();
		}
		
		/**
		 * 跳到指定帧并且停止播放, 帧计数从 0 开始
		 * @param	frame 跳到的指定帧
		 */
		public function gotoAndStop(frame : int) : void
		{
			m_isPlaying = false;
			m_currentFrame = frame;
			createNewFrame(m_currentFrame);
		}
		
		/**
		 * 更新帧, 通过计时器更新当前渲染帧
		 */
		public function update() : void
		{
			if (!m_isFinished && m_isPlaying && m_timer.update())
			{
				if (!m_isPlayback)
				{
					if (++m_currentFrame == m_totalFrame)
					{
						if (m_repeatCount != 0)
						{
							--m_repeatCount;
							m_currentFrame = 0;
						}
						else
						{
							m_isFinished = true;
							m_currentFrame = m_totalFrame - 1;
							this.dispatchEvent(new KAnimatorEvent(KAnimatorEvent.PLAY_END, m_currentFrame));
							return;
						}
					}
				}
				else
				{
					if (--m_currentFrame == -1)
					{
						if (m_repeatCount != 0)
						{
							--m_repeatCount;
							m_currentFrame = m_totalFrame - 1;
						}
						else
						{
							m_isFinished = true;
							m_currentFrame = 0;
							this.dispatchEvent(new KAnimatorEvent(KAnimatorEvent.PLAY_END, m_currentFrame));
							return;
						}
					}
				}
				
				createNewFrame(m_currentFrame);
				this.dispatchEvent(new KAnimatorEvent(KAnimatorEvent.UPDATE_FRAME, m_currentFrame));
				
			} // enf if (m_isPlaying)
		}
		
		/// 获得当前帧, 帧计数从 0 开始
		public function getCurrentFrame() : int
		{
			return m_currentFrame;
		}
		
		/// 获得总帧数
		public function getTotalFrame() : int
		{
			return m_totalFrame;
		}
		
		/// 获得重复播放次数
		public function getRepeatCount() : int
		{
			return m_repeatCount < 0 ? -1 : m_repeatCount;
		}
		
		/// 获得动画是否播放结束
		public function isFinished() : Boolean
		{
			return m_isFinished;
		}
		
		/// 获得是否还在播放
		public function isPlaying() : Boolean
		{
			return m_isPlaying;
		}
		
		/// 获得是否倒序播放
		public function isPlayback() : Boolean
		{
			return m_isPlayback;
		}
		
		/**
		 * 获得指定的渲染帧
		 * @param	frame 指定的帧索引
		 * @return 返回指定帧的数据
		 */
		public function getDisplayFrame(frame : int) : KFrameInfo
		{
			if (frame < 0 || frame >= m_totalFrame)
				throw new ArgumentError("KBitmapAnimator.getDisplayFrame 指定的 frame 数据超出有效范围");
				
			return m_animatorInfo.getFrameInfo(frame);
		}
		
		/**
		 * 每帧间隔时间
		 */
		public function get duration() : Number
		{
			return m_timer.duration;
		}
		
		public function set duration(value : Number) : void
		{
			m_timer.duration = value;
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 实现 IDispose
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/// 释放资源
		public function dispose() : void
		{
			if (m_isDisposed)
				return;
			m_isDisposed = true;
			
			m_animatorInfo = null;
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 实现 IKClonable
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * 生成克隆动画
		 * @return KBitmapAnimator 需要强制类型转换
		 */
		public function clone() : IKClonable
		{
			return new KBitmapAnimator(m_animatorInfo, m_timer.duration);
		}

///////////////////////////////////////////////////////////////////////////////////////////////////
// 私有域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * 显示指定帧的位图
		 * @param	currentFrame 显示的帧
		 */
		private function createNewFrame(frame : int) : void
		{
			var frameInfo : KFrameInfo = m_animatorInfo.getFrameInfo(frame);
			var texture : KTexture2D = frameInfo.texture;
			var bmpData : BitmapData = texture.bitmapData;
			
			if (bmpData != this.bitmapData)
			{
				var temp : Boolean = this.smoothing;
				this.bitmapData = bmpData;
				
				// 改变位图数据会改变 smoothing 属性的值
				if (temp && (temp != this.smoothing))
					this.smoothing = true;
					
				this.dispatchEvent(new KAnimatorEvent(KAnimatorEvent.RENDER_FRAME, frame));
			}
		}
		
		/// 动画数据信息
		private var m_animatorInfo : KBitmapAnimatorInfo = null;
		
		/// 当前播放帧
		private var m_currentFrame : int = 0;
		
		/// 总帧数
		private var m_totalFrame : int = 0;
		
		/// 播放重复的次数, -1无限播放
		private var m_repeatCount : int = 0;
		
		/// 动画是否播放完, isFinished 优先级高于 isPlaying, 所以当动画播放结束的时候, pause 与 resume 函数将没有作用
		private var m_isFinished : Boolean = false;
		
		/// 动画是否在播放
		private var m_isPlaying : Boolean = false;
		
		/// 动画是否在倒序播放
		private var m_isPlayback : Boolean = false;
		
		/// 判断是否释放资源
		private var m_isDisposed : Boolean = false;
		
		/// 动画计时器
		private var m_timer : AnimatorTimer = null;
	}

}

import iks.utils.*;

class AnimatorTimer
{
	/**
	 * 构造函数
	 * @param	elapse 每帧已经过时间
	 * @param	duration 每帧的间隔时间
	 */
	public function AnimatorTimer(duration : Number)
	{
		m_elapse = 0.0;
		m_duration = duration;
	}
	
	/**
	 * 重新计时
	 */
	public function reset() : void
	{
		m_elapse = 0.0;
	}
	
	/**
	 * 更新计时器
	 * @return true 表示达到duration, 否则 false
	 */
	public function update() : Boolean
	{
		m_elapse += KTimerManager.interval;
		if (m_elapse >= m_duration)
		{
			m_elapse = 0.0;
			return true;
		}
		
		return false;
	}
	
	/**
	 * 间隔时间
	 */
	public function get duration() : Number
	{
		return m_duration;
	}
	
	public function set duration(value : Number) : void
	{
		m_duration = value;
		m_elapse = 0.0;
	}
	
	private var m_elapse : Number = 0.0;
	private var m_duration : Number = 0.0;
}































///////////////////////////////////////////////////////////////////////////////////////////////////
// end file


